package cn.xyf.mzmy.common.netty.core.handler;

import cn.hutool.core.util.StrUtil;
import cn.xyf.mzmy.common.netty.core.message.RegisterMessage;
import cn.xyf.mzmy.common.netty.core.message.ResponseMessage;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import static cn.xyf.mzmy.common.netty.core.constant.TypeConstants.PING;
import static cn.xyf.mzmy.common.netty.core.constant.TypeConstants.REGISTER;

@Slf4j
@Component
public class TextWebSocketFrameHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {


    // 存储用户ID与ChannelHandlerContext的映射关系，用于主动推送消息
    // 使用ConcurrentHashMap保证线程安全
    public static final ConcurrentMap<String, ChannelHandlerContext> userChannels = new ConcurrentHashMap<>();

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof WebSocketServerProtocolHandler.HandshakeComplete) {
            log.info("WebSocket handshake completed for channel: {}", ctx.channel().id().asShortText());
            // 握手完成后，通常会等待客户端发送注册消息（包含userId）
        } else {
            super.userEventTriggered(ctx, evt);
        }
    }

    @Override
    public void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
        String text = msg.text();
        log.info("Received message: {}", text);
        try {
            JSONObject jsonObject = JSON.parseObject(text);
            String type = jsonObject.getString("type");

            if (REGISTER.getValue().equals(type)) {
                // String userId = jsonObject.getString("userId");
                RegisterMessage registerMessage = jsonObject.to(RegisterMessage.class);
                String userId = registerMessage.getUserId();
                if (StrUtil.isNotBlank(userId)) {
                    // 将用户ID与当前ChannelHandlerContext关联
                    userChannels.put(userId, ctx);
                    log.info("User {} registered with channel {}", userId, ctx.channel().id().asShortText());
                    // 可以发送确认消息给客户端
                    ResponseMessage responseMessage = ResponseMessage.builder().type("register_ack").message("Registration successful").build();
                    ctx.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(responseMessage)));
                } else {
                    log.warn("Registration failed: Missing userId");
                    ResponseMessage responseMessage = ResponseMessage.builder().type("error").message("Missing userId").build();
                    ctx.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(responseMessage)));
                }
            } else if (PING.getValue().equals(type)) {
                // 回应心跳
                ctx.writeAndFlush(new TextWebSocketFrame("{\"type\": \"pong\"}"));
            } else {
                log.warn("Unknown message type: {}", type);
                ResponseMessage responseMessage = ResponseMessage.builder().type("error").message("Unknown message type").build();
                ctx.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(responseMessage)));
            }
        } catch (Exception e) {
            log.error("Error processing message: {}", text, e);
            ResponseMessage responseMessage = ResponseMessage.builder().type("error").message("Invalid message format").build();
            ctx.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(responseMessage)));
        }
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        log.info("Channel removed: {}", ctx.channel().id().asShortText());
        // 当连接断开时，从映射中移除对应的用户
        userChannels.values().removeIf(context -> context.equals(ctx));
        super.handlerRemoved(ctx);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        log.error("Exception caught in channel {}: {}", ctx.channel().id().asShortText(), cause.getMessage(), cause);
        ctx.close(); // 关闭连接
    }

    // 提供一个静态方法供Spring Boot其他部分调用，向特定用户发送消息
    public static void sendMessageToUser(String userId, String message) {
        ChannelHandlerContext ctx = userChannels.get(userId);
        if (ctx != null && ctx.channel().isActive()) {
            ctx.writeAndFlush(new TextWebSocketFrame(message));
            log.info("Message sent to user {}: {}", userId, message);
        } else {
            log.warn("Failed to send message to user {}: Channel not found or inactive", userId);
        }
    }
}